<?php

class Jnd_Controller_Action_Upload extends Jnd_Controller_Action
{
    protected $options;

    function init()
    {
        $this->setOptions();
    }

    public function setOptions( $options = null )
    {
        $this->options = array(
            'script_url' => $_SERVER['PHP_SELF'], 
            'upload_dir' => realpath(APPLICATION_PATH . "/../docs") . DIRECTORY_SEPARATOR, 
            'upload_url' => '/default/upload/recup/file/', 
            'param_name' => 'files', 
            // The php.ini settings upload_max_filesize and post_max_size
            // take precedence over the following max_file_size setting:
            'max_file_size' => null, 
            'min_file_size' => 1, 
            'accept_file_types' => '/.+$/i', 
            'max_number_of_files' => null, 
            'discard_aborted_uploads' => true, 
            'image_versions' => array(
                // Uncomment the following version to restrict the size of
                // uploaded images. You can also add additional versions with
                // their own upload directories:
                /*
                'large' => array(
                    'upload_dir' => dirname(__FILE__).'/files/',
                    'upload_url' => dirname($_SERVER['PHP_SELF']).'/files/',
                    'max_width' => 1920,
                    'max_height' => 1200
                ),
                */
                'thumbnail' => array(
                    'upload_dir' => realpath(APPLICATION_PATH . "/galerie/thumbs/") . DIRECTORY_SEPARATOR, 
                    'upload_url' => '/default/upload/recupthumbnail/thumbnails/1/file/', 
                    'max_width' => 80, 
                    'max_height' => 80
                )
            )
        );
        
        //@todo: En php 5.3 : remplacer array_merge par array_replace_recursive
        if ($options) {
            $this->options = array_merge($this->options, $options);
        }
    }

    protected function replaceParam( $value, $params = null )
    {
        if (is_null($params)) {
            $params = $this->getParams();
        }
        if (strpos($value, "{") !== false) {
            preg_match_all('/{[[:alpha:]]+}/', $value, $matches);
            foreach ($matches[0] as $match) {
                $match = (is_string($match) ? $match : $match[0]);
                $parametre = substr($match, 1, strlen($match) - 2);
                $replaceMatch = $params[strtolower($parametre)];
                $value = str_replace($match, $replaceMatch, $value);
            }
        }
        return $value;
    }

    private function get_file_object( $file_name = null )
    {
        $params = $this->getParams();
        if (is_null($file_name)) {
            $file_name = $params["file"];
        }
        
        $file_path = $this->getFilePath($this->options, $file_name);
        if (is_file($file_path) && $file_name[0] !== '.') {
            $file = new stdClass();
            $file->name = $file_name;
            $file->size = filesize($file_path);
            $file->url = $this->replaceParam($this->options['recup_url'] . rawurlencode($file->name), $params);
            foreach ($this->options['image_versions'] as $version => $options) {
                $fichier = $this->getFilePath($options, str_replace(".pdf", ".png", $file_name));
                if (is_file($fichier)) {
                    $file->{$version . '_url'} = $this->replaceParam($options['upload_url'] . str_replace(".pdf", ".png", rawurlencode($file->name)), $params);
                }
            }
            $file->delete_url = $this->replaceParam($this->options['upload_url'] . rawurlencode($file->name), $params);
            $file->delete_type = 'DELETE';
            return $file;
        }
        return null;
    }

    private function get_file_objects()
    {
        
        $listeFichiers = scandir($this->getFilePath($this->options, ""));
        return array_values(array_filter(array_map(array(
            $this, 
            'get_file_object'
        ), $listeFichiers)));
    }

    private function create_scaled_image( $file_name, $options )
    {
        $extension = strtolower(substr(strrchr($file_name, '.'), 1));
        
        if ($extension == "pdf") {
            $iconPdf = realpath(APPLICATION_PATH . "/../public/images/pdf-icon.png");
            $file_path = $iconPdf;
            $new_file_path = $options['upload_dir'] . str_replace(".pdf", ".png", $file_name);
        } else {
            $file_path = $this->options['upload_dir'] . $file_name;
            $new_file_path = $options['upload_dir'] . $file_name;
        }
        
        list ($img_width, $img_height) = @getimagesize($file_path);
        if (! $img_width || ! $img_height) {
            return false;
        }
        $scale = min($options['max_width'] / $img_width, $options['max_height'] / $img_height);
        if ($scale > 1) {
            $scale = 1;
        }
        $new_width = $img_width * $scale;
        $new_height = $img_height * $scale;
        $new_img = @imagecreatetruecolor($new_width, $new_height);
        
        switch ($extension)
        {
            case 'jpg':
            case 'jpeg':
                $src_img = @imagecreatefromjpeg($file_path);
                $write_image = 'imagejpeg';
            break;
            case 'gif':
                $src_img = @imagecreatefromgif($file_path);
                $write_image = 'imagegif';
            break;
            case 'png':
                $src_img = @imagecreatefrompng($file_path);
                $write_image = 'imagepng';
            break;
            case 'pdf':
                $src_img = @imagecreatefrompng($iconPdf);
                imagealphablending($src_img, false); // setting alpha blending on
                imagesavealpha($src_img, true); // save alphablending setting (important)
                $write_image = 'imagepng';
            break;
            default:
                $src_img = $image_method = null;
        }
        $success = $src_img && @imagecopyresampled($new_img, $src_img, 0, 0, 0, 0, $new_width, $new_height, $img_width, $img_height) && $write_image($new_img, $new_file_path);
        // Free up memory (imagedestroy does not delete files):
        @imagedestroy($src_img);
        @imagedestroy($new_img);
        return $success;
    }

    private function has_error( $uploaded_file, $file, $error )
    {
        if ($error) {
            return $error;
        }
        if (! preg_match($this->options['accept_file_types'], $file->name)) {
            return 'acceptFileTypes';
        }
        if ($uploaded_file && is_uploaded_file($uploaded_file)) {
            $file_size = filesize($uploaded_file);
        } else {
            $file_size = $_SERVER['CONTENT_LENGTH'];
        }
        if ($this->options['max_file_size'] && ($file_size > $this->options['max_file_size'] || $file->size > $this->options['max_file_size'])) {
            return 'maxFileSize';
        }
        if ($this->options['min_file_size'] && $file_size < $this->options['min_file_size']) {
            return 'minFileSize';
        }
        if (is_int($this->options['max_number_of_files']) && (count($this->get_file_objects()) >= $this->options['max_number_of_files'])) {
            return 'maxNumberOfFiles';
        }
        return $error;
    }

    private function handle_file_upload( $uploaded_file, $name, $size, $type, $error )
    {
        $params = $this->getParams();
        $file = new stdClass();
        // Remove path information and dots around the filename, to prevent uploading
        // into different directories or replacing hidden system files.
        // Also remove control characters and spaces (\x00..\x20) around the filename:
        $file->name = trim(basename(stripslashes($name)), ".\x00..\x20");
        $file->size = intval($size);
        $file->type = $type;
        $error = $this->has_error($uploaded_file, $file, $error);
        if (! $error && $file->name) {
        	//$extension = substr($file->name, strpos($file->name,".")+1);;
        	$file->name = $this->getSpecificFilename($file);
            $file_path = $this->options['upload_dir'] . $file->name;
            $append_file = is_file($file_path) && $file->size > filesize($file_path);
            clearstatcache();
            if ($uploaded_file && is_uploaded_file($uploaded_file)) {
                // multipart/formdata uploads (POST method uploads)
                if ($append_file) {
                    file_put_contents($file_path, fopen($uploaded_file, 'r'), FILE_APPEND);
                } else {
                    move_uploaded_file($uploaded_file, $file_path);
                }
            } else {
                // Non-multipart uploads (PUT method support)
                file_put_contents($file_path, fopen('php://input', 'r'), $append_file ? FILE_APPEND : 0);
            }
            $file_size = filesize($file_path);
            if ($file_size === $file->size) {
                $file->url = $this->replaceParam($this->options['recup_url'] . rawurlencode($file->name), $params);
                foreach ($this->options['image_versions'] as $version => $options) {
                    if ($this->create_scaled_image($file->name, $options)) {
                        $file->{$version . '_url'} = $this->replaceParam($options['upload_url'] . rawurlencode($file->name), $params);
                    }
                }
            } else if ($this->options['discard_aborted_uploads']) {
                unlink($file_path);
                $file->error = 'abort';
            }
            $file->size = $file_size;
            $file->delete_url = $this->replaceParam($this->options['upload_url'] . rawurlencode($file->name), $params);
            $file->delete_type = 'DELETE';
        } else {
            $file->error = $error;
        }
        return $file;
    }

    public function get()
    {
        $request = $this->getRequest();
        $filename = $request->getParam("file", null);
        if (! is_null($filename)) {
            $filename = basename(stripslashes($filename));
        }
        if ($filename) {
            $info = $this->get_file_object($filename);
        } else {
            $info = $this->get_file_objects();
        }
        header('Content-type: application/json');
        echo json_encode($info);
    }

    public function post()
    {
        $upload = isset($_FILES[$this->options['param_name']]) ? $_FILES[$this->options['param_name']] : array(
            'tmp_name' => null, 
            'name' => null, 
            'size' => null, 
            'type' => null, 
            'error' => null
        );
        $info = array();
        if (is_array($upload['tmp_name'])) {
            foreach ($upload['tmp_name'] as $index => $value) {
                $info[] = $this->handle_file_upload($upload['tmp_name'][$index], isset($_SERVER['HTTP_X_FILE_NAME']) ? $_SERVER['HTTP_X_FILE_NAME'] : $upload['name'][$index], isset($_SERVER['HTTP_X_FILE_SIZE']) ? $_SERVER['HTTP_X_FILE_SIZE'] : $upload['size'][$index], isset($_SERVER['HTTP_X_FILE_TYPE']) ? $_SERVER['HTTP_X_FILE_TYPE'] : $upload['type'][$index], $upload['error'][$index]);
            }
        } else {
            $info[] = $this->handle_file_upload($upload['tmp_name'], isset($_SERVER['HTTP_X_FILE_NAME']) ? $_SERVER['HTTP_X_FILE_NAME'] : $upload['name'], isset($_SERVER['HTTP_X_FILE_SIZE']) ? $_SERVER['HTTP_X_FILE_SIZE'] : $upload['size'], isset($_SERVER['HTTP_X_FILE_TYPE']) ? $_SERVER['HTTP_X_FILE_TYPE'] : $upload['type'], $upload['error']);
        }
        header('Vary: Accept');
        if (isset($_SERVER['HTTP_ACCEPT']) && (strpos($_SERVER['HTTP_ACCEPT'], 'application/json') !== false)) {
            header('Content-type: application/json');
        } else {
            header('Content-type: text/plain');
        }
        echo json_encode($info);
    }

    public function delete()
    {
        $params = $this->getParams();
        $request = $this->getRequest();
        $filename = $request->getParam("file", null);
        if (! is_null($filename)) {
            $filename = basename(stripslashes($filename));
        }
        $file_path = $this->getFilePath($this->options, $filename);
        $success = is_file($file_path) && $filename[0] !== '.' && unlink($file_path);
        if ($success) {
            foreach ($this->options['image_versions'] as $version => $options) {
                $file = $this->getFilePath($options, $filename);
                if (is_file($file)) {
                    unlink($file);
                }
            }
        }
        header('Content-type: application/json');
        echo json_encode($success);
    }

    public function uploadAction()
    {
        $this->desactivationRendu();
        header('Pragma: no-cache');
        header('Cache-Control: private, no-cache');
        header('Content-Disposition: inline; filename="files.json"');
        header('X-Content-Type-Options: nosniff');
        
        $request = $this->getRequest();
        $type = $request->getParam("type", null);
        $categorie = $request->getParam("categorie", null);
        $id = $request->getParam("id", 0);
        
       $filename = $this->getFileRacine($categorie, $id);
        
        switch ($_SERVER['REQUEST_METHOD'])
        {
            case 'HEAD':
            case 'GET':
                $this->get();
            break;
            case 'POST':
                if (is_null($type)) {
                    header('HTTP/1.0 405 Method Not Allowed');
                    die();
                } else {
                    $uploadDir = $this->options['upload_dir'];
                    $uploadDir .= $this->getSpecificRep();
                    if (! is_dir($uploadDir)) {
                        mkdir($uploadDir, 0777, true);
                    }
                    $this->options['upload_dir'] = $uploadDir;
                    foreach ($this->options['image_versions'] as $version => $options) {
                        $options['version'] = $version;
                        $uploadDir = $options['upload_dir'];
                        $uploadDir .= $this->getSpecificRep(array('version' => $version));
                        
                        if (! is_dir($uploadDir)) {
                            mkdir($uploadDir, 0777, true);
                        }
                        $this->options['image_versions'][$version]['upload_dir'] = $uploadDir;
                    }
                
                }
                $this->post();
            break;
            case 'DELETE':
                $this->delete();
            break;
            case 'OPTIONS':
            break;
            default:
                header('HTTP/1.0 405 Method Not Allowed');
        }
    }
    
    public function getFileRacine($categorie) {
    	return "";
    }
    
    public function getSpecificRep($options = array()) {
        return $options['version'];
    }

    public function recupthumbnailAction()
    {
        $this->desactivationRendu();
        $params = $this->getParams();
        $fichier = $params['file'];
        $thumbnails = $params["thumbnails"];
        if ($thumbnails === false) {
            $this->get();
        } else {
            $optionsThb = $this->options['image_versions']['thumbnail'];
            if (is_file($optionsThb['upload_dir'] . $fichier)) {
                echo file_get_contents($optionsThb['upload_dir'] . $fichier);
            }
        }
    }

    public function recupAction()
    {
        $this->desactivationRendu();
        $params = $this->getParams();
        $fichier = $params['file'];
        $type = $params['type'];
        $id = $params['id'];
        
        if (! is_null($fichier)) {
            $filepath = $this->getFilePath($this->options, $fichier);
            if (file_exists($filepath)) {
                switch (strtolower(substr(strrchr($fichier, '.'), 1)))
                {
                    case 'pdf':
                        $mime = 'application/pdf';
                    break;
                    case 'zip':
                        $mime = 'application/zip';
                    break;
                    case 'jpeg':
                    case 'jpg':
                        $mime = 'image/jpg';
                    break;
                    default:
                        $mime = 'application/force-download';
                }
                header('Pragma: public'); // required
                header('Expires: 0'); // no cache
                header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
                header('Last-Modified: ' . gmdate('D, d M Y H:i:s', filemtime($filepath)) . ' GMT');
                header('Cache-Control: private', false);
                header('Content-Type: ' . $mime);
                header('Content-Disposition: attachment; filename="' . basename($filepath) . '"');
                header('Content-Transfer-Encoding: binary');
                header('Content-Length: ' . filesize($filepath)); // provide file size
                header('Connection: close');
                readfile($filepath); // push it out
                exit();
            } else {
                die(__("Le fichier est introuvable sur le serveur ...."));
            }
            echo "Fichier '$fichier' - FilePath : $filepath";
        } else {
            die(__("Le fichier est introuvable"));
        }
    }

    protected function getParams()
    {
        $request = $this->getRequest();
        $params['file'] = $request->getParam("file", null);
        $params['thumbnails'] = $request->getParam("thumbnails", null);
        return $params;
    }

    protected function getFilePath( $options, $filename )
    {
        return $options['upload_dir'] . $filename;
    }
    
    protected function getSpecificFilename($file) {
        return $file->name;
    }
}
